function Tree(id, DataMethodType, DataMethodName)
{
	this.TreeData=null;
	this.NoData='No Data.';
	this.Action='None';

	var Content=el(id+'_Content');
	var This=this;
	var CurrentTitleId=null;
	this.LevelCss=['TreeLevel1','TreeLevel2'];
	this.HighlightLastTitleClicked=null;
	var MinusImg = ImageUrl('TreeMinus.gif');
	var MinusImgL = ImageUrl('TreeMinusLast.gif');
	var PlusImg=ImageUrl('TreePlus.gif');
	var PlusImgL = ImageUrl('TreePlusLast.gif');
	var FailureImg = ImageUrl('Failure.gif');
	this.BoxSelectedNode = false;
	this.Lines = true;
	var CurrentBoxId;
	this.GetData = function(nid)
	{
		this.TreeData = this.GetSelectedData();
		var request = {};
		var ti = {};
		if (!nid)
		{
			ShowLoading(Content);
		}
		else
		{
			var n = this.GetNode(nid);
			if (n)
			{
				var con = el(this.GetContentId(n.idx));
				if (con)
					ShowLoading(con);
			}
			ti.Path = nid;
		}
		request.DataMethodType = DataMethodType;
		request.DataMethodName = DataMethodName;
		ti.Action = this.Action;
		ti.Parameters = this.GetParameters();
		if (!nid)
			ti.Data = this.TreeData;
		request.TreeInfo = ti;
		Web.Ajax.Controls.Tree.GetData(request, this.SetData);
	}
	this.SetData=function(r)
	{
		if(r.Path)
		{
			This.RenderNodeContent(r.Path,r.Data, r.Message);
			return;
		}
		This.TreeData=r.Data;
		This.Render(r.Message);
		if (r.OnComplete)
			eval(r.OnComplete);
		This.Action = 'None';
	}
	this.GetNode=function(nid, td, idx, pid)
	{
		if(!td)
			td=this.TreeData;
		if(!td)
			return null;
		for(var i=0;i<td.length;i++)
		{
			var n=td[i];
			n.idx=(idx?(idx+'_'):'')+i;
			n.pid=pid;
			if(n.Id==nid)
				return n;
			if(!n.Children)
				continue;
			n=this.GetNode(nid,n.Children,n.idx, n.Id);
			if(n!=null)
				return n;
		}
		return null;
	}
	this.AddNode=function(node, pid)
	{
		if(!node)
			return;
		var pn, a;
		if(pid)
			pn=this.GetNode(pid);
		if(pn)
			a=pn.Children;
		else
			a=this.TreeData;
		if(!a)
		{
			a=[];
			if(pn)
				pn.Children=a;
			else
				this.TreeData=a;
		}
		a[a.length]=node;
		if(pn)
			this.RefreshNode(pid);//	this.RenderNodeContent(pid, pn.Children);
		else 
			this.Render();
	}
	this.DeleteNode=function(nid)
	{
		var n=this.GetNode(nid);
		if(n)
		{
			var arr=this.TreeData;
			if(n.pid)
			{
				var p=this.GetNode(n.pid);
				if(p)
					arr=p.Children;
			}
			var idx=-1;
			if(arr)
			{
				for(var i=0;i<arr.length;i++)
				{
					if(arr[i].Id==nid)
					{
						idx=i;
						break;
					}
				}
			}
			if(idx>-1)
				arr.splice(idx,1);
			if(n.pid)
				this.RefreshNode(n.pid);
		}
	}

	this.Toggle = function(idx, img, nid)
	{
		var cid = this.GetContentId(idx)
		var e = el(cid);
		var d = e.style.display;
		var n = this.GetNode(nid);
		if (!d || d == 'block')
		{
			e.style.display = 'none';
			var pi = PlusImg;
			if (img.src.indexOf('Last') != -1)
				pi = PlusImgL;
			img.src = pi;
			if (n)
				n.Collapse = true;
		}
		else
		{
			e.style.display = 'block';
			var mi = MinusImg;
			if (img.src.indexOf('Last') != -1)
				mi = MinusImgL;
			img.src = mi; 
			if (n)
			{
				n.Collapse = false;
				if (n.Children == null && n.Ajax)
				{
					ShowLoading(e);
					this.GetData(nid);
				}
			}
		}
	}
	this.GetLevelCss=function(nid)
	{
		var l=(''+nid).split('_').length-1;
		if(l<this.LevelCss.length)
			return this.LevelCss[l];
		return this.LevelCss[this.LevelCss.length-1];
	}
	this.GetNodeId=function(nid)
	{
		return (id+'_Node_'+nid);
	}
	this.GetContentId=function(nid)
	{
		return (id+'_Content_'+nid);
	}
	this.GetValidatorId=function(nid)
	{
		return (id+'_val_'+nid);
	}
	this.GetSelectorId=function(nid)
	{
		return (id+'_sel_'+nid);
	}
	this.GetTitleId=function(nid)
	{
		return (id+'_tit_'+nid);
	}
	this.SetNodeIcon=function(nid, r)
	{
		var n=this.GetNode(nid);
		if(n)
		{
			n.Resource=r;
			var icon=el(nid+'.Icon');
			if(icon)
				icon.src=ImageUrl(n.Resource);
		}
	}
	this.GetTitle=function(nid)
	{
		var n = this.GetNode(nid);
		if (n)
			return n.Title;
	}
	this.SetTitle = function(nid, t)
	{
		var n = this.GetNode(nid);
		if (n)
		{
			n.Title = t;
			var te = el(this.GetTitleId(n.idx));
			te.innerHTML = t;
		}
	}
	this.RenderOnTitleClick=function(n,nidx)
	{
		var html='';
		var tc=n.OnTitleClick;
		var nid=n.Id;
		if(n.Id)
			nid=nid.replace(/\\/g,'\\\\');
		if(tc)
		{
			tc=tc.replace(/params/g,nid);
			tc=tc.replace(/string/g,'\''+nid+'\'');
		}
		html+='onclick="'+(id+'.OnTitleClick(\''+nidx+'\', this);')+nonull(tc)+'" ';

		/*
		if(n.Options)
			html+='oncontextmenu="'+(id+'.RenderOptionsPopup(\''+n.Id+'\',this, event);return false;')+'" title="Right click to view options."';
		else
			html += 'oncontextmenu="return false;"';
		*/
		return html;
	}
	this.RenderTitleOptions = function(n, nidx) {
		var html = ''
		if (!n.Options || n.Options.Items==null||n.Options.Items.length == 0)
			return html;
		return '<span style="width: 16px"><img class="vam hand" src="resource.axd?SortedAsc.gif" onclick="' + (id + '.RenderOptionsPopup(\'' + n.Id + '\',this, event);return false;') + '" /></span>';
	}
	this.RenderOnDblClick=function(n)
	{
		if(n.OnDblClick)
			return 'ondblclick="'+n.OnDblClick+'"';
		return '';
	}
	this.OnTitleClick=function(idx, src)
	{
		var id;
		if(this.HighlightLastTitleClicked)
		{
			id=this.GetTitleId(idx);
			var te=el(CurrentTitleId);
			if(te)
				te.className='TreeTitle';
			CurrentTitleId=id;
			var te=el(CurrentTitleId);
			if(te)
				te.className='TreeTitleHighlight';
		}
		if(this.BoxSelectedNode)
		{
			id=this.GetNodeId(idx);
			$(el(CurrentBoxId)).removeClass('TreeBox');
			CurrentBoxId=id;
			$(el(id)).addClass('TreeBox');
		}
	}
	
	this.RenderLinkClick=function(n,l)
	{
		var html='';
		if(l.OnClick)
		{
			var c=l.OnClick;
			c=c.replace(/params/g,n.Id);
			c=c.replace(/string/g,'\''+n.Id+'\'');
			html+='onclick="'+c+'"';
		}
		else if(l.Url)
			html+='onclick="location.href=\''+l.Url+'\'"';
		return html;
	}
	this.RenderNodeLinks=function(n)
	{
		var html='<div>';
		for(var i=0;i<n.Links.length;i++)
		{
			var l=n.Links[i];
			var click=l.OnClick
			html+='<span class="TreeLink" '+this.RenderLinkClick(n,l)+'>'+l.Text+'</span>';
		}
		html+='</div>';
		return html;
	}
	this.RenderNodeHeading = function(o, pid, nid, m, min, l) {
		var tw = 'width:100%;';
		if (this.Browser == 'IE6')
			tw = 'table-layout:fixed;';
		var html = '<table cellspacing="0" style="' + tw + '"><tr>';
		if (o.Children || o.Ajax)
			html += '<td style="width:16px;cursor:pointer;">' + ImageHtml(o.Collapse ? (l ? PlusImgL : PlusImg) : (l ? MinusImgL : MinusImg), null, id + '.Toggle(\'' + nid + '\',this,\'' + (o.Id ? o.Id.replace(/\\/g, '\\\\') : '') + '\');') + '</td>';
		else
			html += '<td style="width:16px;">' + ImageHtml(ImageUrl(this.Lines ? (l ? 'TreeEnd.gif' : 'TreeDent.gif') : 'NullIcon.gif')) + '</td>';
		if (o.Resource)
			html += '<td style="width:16px;' + (o.Children ? '' : 'padding-left:3px;') + '" ' + this.RenderOnTitleClick(o, nid) + '>' + ImageHtml(ResourceUrl(o.Resource), null, null, null, o.Id + '.Icon'); +'</td>';
		var val = '';
		if (m || o.Selectable)//Parent Max != 0
		{
			var sid = this.GetSelectorId(nid);
			var name = (m == 1) ? this.GetSelectorId(pid + '_sn') : sid;
			html += '<td style="width:20px;text-align:center;vertical-align:middle;">';
			html += '<input class="TreeSelector" type="' + ((m == 1 && min == 1) ? 'radio' : 'checkbox') + '" name="' + name + '" id="' + sid + '" ' + (o.Selected ? 'checked' : '') + ' />';
			html += '</td>';
		}
		var vid = this.GetValidatorId(nid);
		val = '&nbsp;' + ImageHtml(FailureImg, 'TreeValidator', null, 'You must select Min: ' + o.Min + ' Max: ' + o.Max, vid);
		var TitleCss = 'TreeTitle';
		var TitleId = this.GetTitleId(nid);
		if (o.CurrentTitle) {
			TitleCss = 'TreeTitleHighlight';
			CurrentTitleId = TitleId;
		}
		if (o.State == 'n')
			TitleCss += ' TreeTitleNew';
		if (o.State == 'm')
			TitleCss += ' TreeTitleModified';
		html += '<td>';
		var ttag = (o.Title.indexOf('<br>') == -1 ? 'span' : 'div');
		html += '<' + ttag + ' class="' + TitleCss + '" id="' + TitleId + '" ' + this.RenderOnTitleClick(o, nid) + ' ' + this.RenderOnDblClick(o) + ' style="' + (o.TitleWidth ? 'width:' + o.TitleWidth + ';' : '') + (o.OnTitleClick ? 'cursor:pointer;' : '') + '">' + o.Title + '</' + ttag + '>';
		html += this.RenderTitleOptions(o, nid);
		html += '</td>';
		if (o.Children)
			html += '<td class="TreeValidatorCell">' + val + '</td>';
		if (o.Data)
			html += '<td class="TreeData" style="' + (o.DataWidth ? 'width:' + o.DataWidth : '') + '">' + o.Data + '</td>';
		if (o.Links) {
			html += '<td style="text-align:right;' + (o.LinkSectionWidth ? 'width:' + o.LinkSectionWidth + ';' : '') + '">';
			html += this.RenderNodeLinks(o);
			html += '</td>'
		}
		html += '</tr></table>'
		return html;
	}
	this.RenderNode = function(o, pid, nid, max, min, l)
	{
		o.pid = pid;
		o.idx = nid;
		var css = this.GetLevelCss(nid);
		var ncss = '';
		if (this.Lines && l)
			ncss = 'TreeCover';
		if (o.Css)
			ncss += o.Css;
		var html = '<div id="' + this.GetNodeId(nid) + '" class="' + ncss + '">';
		html += '<div class="' + css + '">';
		html += this.RenderNodeHeading(o, pid, nid, max, min, l);
		html += '</div>';
		html += '<div id="' + this.GetContentId(nid) + '" class="' + (o.ContentCss ? o.ContentCss : 'TreeLevelContent') + '" ' + ((o.Collapse || !o.Children) ? 'style="display:none;"' : '') + '>';
		if (o.Children)
		{
			for (var j = 0; j < o.Children.length; j++)
			{
				var cnid = nid + '_' + j;
				html += this.RenderNode(o.Children[j], nid, cnid, o.Max, o.Min, (j == o.Children.length - 1));
			}
		}
		html += '</div>';
		html += '</div>';
		return html;
	}
	this.RefreshNode=function(nid)
	{
		var n=this.GetNode(nid);
		if(!n)
			return;
		var p=n.pid?this.GetNode(n.pid):null;
		var div=el(this.GetNodeId(n.idx));
		if(div)
			div.innerHTML=this.RenderNode(n, (p?p.idx:''), n.idx, (p?p.Max:null), (p?p.Min:null));
	}
	this.RenderNodeContent = function(nid, d, error)
	{
		var n = this.GetNode(nid);
		if (!n)
			return;
		var nidx = n.idx;
		n.Children = d;
		var html = '';
		if (error)
		{
			html = '<div class="Error">' + error + '</div>';
		}
		else
		{
			if (n.Children && n.Children.length > 0)
			{
				for (var i = 0; i < n.Children.length; i++)
				{
					var cnidx = nidx + '_' + i;
					html += this.RenderNode(n.Children[i], nidx, cnidx, n.Max, n.Min, (i == n.Children.length - 1));
				}
			}
			else
			{
				html += this.RenderNode({ Title: 'No Data', Css:'NoData' }, nidx, nidx + '_0', 0, 0, true);
				//html = '<div class="NoData AlignLeft ' + (this.Lines ? '' : 'Pad20Left') + '">' + (this.Lines ? ImageHtml(ImageUrl('TreeEnd.gif')) : '') + this.NoData + '</div>';
			}
		}
		var cid = this.GetContentId(nidx)
		var e = el(cid);
		if (e)
			e.innerHTML = html;
	}
	this.Render=function(m)
	{
		var d=this.TreeData;
		var html='';
		if(m)
			html='<div class="Error">'+m+'</div>'
		else
		{
			if(!d||d.length==0)
				html='<div class="NoData">'+this.NoData+'</div>';
			else
			{
				for(var i=0;i<d.length;i++)
				{
					html+=this.RenderNode(d[i],'',i);
				}
			}
		}
		Content.innerHTML=html;
	}
	this.Clear=function()
	{
		this.TreeData=null;
		this.Render();
	}
	this.IsNodeSelected=function(nid)
	{
		var e=el(this.GetSelectorId(nid));
		if(e)
			return e.checked;
		return false;
	}
	this.ValidateNode=function(n, pid, nid)
	{
		var val=true;
		var ve=el(this.GetValidatorId(nid));
		if(!ve)
			return val;
		ve.style.visibility='hidden';
		if(!n.Children)
			return val;
		var count=0;
		for(var i=0;i<n.Children.length;i++)
		{
			var cid=nid+'_'+i;
			val=(this.ValidateNode(n.Children[i],nid,cid)&&val);
			if(this.IsNodeSelected(cid))
				count++;
		}
		if(count<n.Min||count>n.Max)
		{
			ve.style.visibility='visible';
			val=false;
		}
		return val;
	}
	this.Validate=function()
	{
		var d=this.TreeData;
		if(!d||d.length==0)
			return true;
		var val=true;
		for(var i=0;i<d.length;i++)
			val=(this.ValidateNode(d[i],'',i)&&val);
		return val;
	}
	this.UpdateSelectedNodeData=function(n,pid,nid)
	{
		n.Selected=this.IsNodeSelected(nid);
		if(!n.Children)
			return;
		for(var i=0;i<n.Children.length;i++)
			this.UpdateSelectedNodeData(n.Children[i],nid,nid+'_'+i);
	}
	this.GetSelectedData=function()
	{
		var d=this.TreeData;
		if(!d||d.length==0)
			return [];
		for(var i=0;i<d.length;i++)
			this.UpdateSelectedNodeData(d[i],'',''+i);
		return d;
	}
	this.Delete=function()
	{
		this.Action='Delete';
		this.GetData();
	}
	this.FillHeight=function()
	{
		var ds=GetDocSize();
		var te=el(id);
		var rec=GetRec(te);
		if((rec.y+rec.h)<ds.h)
			te.style.height=(ds.h-rec.y-20)+'px';
	}
	this.RenderOptionsPopup = function(nid, src, event) {
		if (!event)
			event = window.event;
		var n = this.GetNode(nid);
		var o = n.Options;
		if (!o || !o.Items)
			return;
		var e = Append('div', id + 'Options', 'PopupMenuPanel');
		var html = '<div class="PopupMenu">';
		//html += '<div class="ar" style="position: absolute; right: 0px; top: -15px; width: 20px; height: 14px; border: solid 1px #ccc; border-bottom: solid 1px #fff;"><img src="resource.axd?ArrowDown.gif"/></div>';
		html += '<div class="ar" style="position: absolute; right: 4px; top: -16px; width: 16px; height: 15px; border: solid 1px #ccc; border-bottom: solid 1px #fff;background-color: #fff;"><img src="resource.axd?ArrowDown.gif"/></div>';
		for (var i = 0; i < o.Items.length; i++) {
			var opt = o.Items[i];
			html += '<div onclick="' + id + '.OptionPopup.Hide();' + opt.OnClick + '" class="MenuItem ' + (opt.Css ? opt.Css : '') + '">' + opt.Text + '</div>';
		}
		html += '</div>';
		if (!this.OptionPopup)
			this.OptionPopup = new PopupMenu(id + 'Options', 5, -1, 'br');
		this.OptionPopup.ShowFromNewSource(src, html);
		//this.OptionPopup.SetPos(event.clientX-20);
		return false;
	}



	this.ConvertObject = function (o, name, pid, rec) {
		if (!o)
			return null;
		var nid = '';
		if (rec) {
			if (pid)//pid!='Old'&&pid!='New')
				nid = pid + '.';
			nid += name;
		}

		var td = { Title: '<b>' + name + ':</b>', Id: nid };
		var ch = [];
		switch (typeof o) {
			case 'string':
				//td.Title += ' \'' + EncodeJson(o) + '\'';
				td.Title += ' \'' + o + '\'';
				break;
			case 'number':
				td.Title += ' ' + String(o);
				break;
			case 'object':
				if (o) {
					if (window.FormatDate && ('Day' in o) && ('Month' in o) && ('Year' in o)) {
						td.Title += ' ' + FormatDate(o);
					}
					else {
						if (o.constructor == Array) {
							for (var i = 0; i < o.length; i++) {
								var ai = this.ConvertObject(o[i], '[' + i + ']', nid, true);
								if (ai)
									ch[ch.length] = ai;
							}
						}
						else {
							var pl = [];
							for (var p in o)
								pl.push(p);
							pl.sort();
							for (var i in pl) {
								var p = pl[i];
								var pi = this.ConvertObject(o[p], p, nid, true);
								if (pi)
									ch[ch.length] = pi;
							}
						}
					}
				}
				break;
			case 'boolean':
				td.Title += ' ' + String(o);
				break;
			case 'function': return null;
			case 'undefined': return null;
		}
		if (ch.length > 0)
			td.Children = ch;
		return td;
	}
	this.SetObject = function(obj, rootname) {
		var td = this.ConvertObject(obj, rootname);
		if (td == null)
			td = {Title:'<b>'+rootname+':</b> null', Id:'null'};
		this.SetData({ Data: [td] });
	}
}
Tree.Compare = function(ot, nt, ntd, recursive) {
	if (nt==null||nt.TreeData == null||nt.TreeData.length!=1)
		return;
	if (ntd == null && recursive)
		return;
	if (ntd == null)
		ntd = nt.TreeData[0].Children;
	for (var i = 0; i < ntd.length; i++) {
		var n = ntd[i];
		var otn = ot.GetNode(n.Id);
		var tid = nt.GetTitleId(n.idx);
		el(tid).style.color = ''
		if (otn == null)	//New
			el(tid).style.backgroundColor = '#8f8';
		else {
			if (otn.Title != n.Title)
				el(tid).style.backgroundColor = '#ff8';
		}
		Tree.Compare(ot, nt, n.Children, true);
	}
}
Tree.prototype=new AjaxControl();